#ifndef OCK_MEMORY_BRIDGE_HMOBJECT_H
#define OCK_MEMORY_BRIDGE_HMOBJECT_H
#include <cstdint>
#include <memory>
#include <vector>
#include "ock/hmm/mgr/OckHmmAsyncResult.h"
#include "ock/hmm/mgr/OckHmmHeteroMemoryLocation.h"

namespace ock {
namespace hmm {

using OckHmmHMOObjectID = uint64_t;
using OckHmmDeviceID = uint16_t;
class OckHmmHMOBufferBase
{

public:
    virtual uintptr_t Address(void) const = 0;
    virtual uint64_t Size(void) const = 0;
};

std::ostream &operator<<(std::ostream &os, OckHmmHMObjectBase &buffer);


class OckHmmHMOBuffer : public OckHmmResultBase, public OckHmmHMOBufferBase
{
public:
   virtual ~OckHmmHMOBuffer() noexcept = default;
   virtual uint64_t Offset(void) const = 0;
   virtual OckHmmHeteroMemoryLocation Location(void) const = 0;
   virtual OckHmmHMOObjectID GetId(void) const = 0;
   virtual OckHmmErrorCode FlushData(void) const = 0;
};

class OckHmmSubHMObject
{
public:
    virtual ~OckHmmSubHMObject() noexcept = default;
    virtual uint64_t GetByteSize(void) const = 0;
    virtual uintptr_t Addr(void) const = 0;
    virtual OckHmmHeteroMemoryLocation Location(void) const = 0;
    virtual std::shared_ptr<OckHmmHMOBuffer> GetBuffer(OckHmmHeteroMemoryLocation location,
        uint64_t offset = 0, uint64_t length = 0, uint32_t timeout = 0) = 0;
    virtual std::shared_ptr<OckHmmHMOBuffer> GetBufferAsync(OckHmmHeteroMemoryLocation location,
        uint64_t offset = 0, uint64_t length = 0, uint32_t timeout = 0) = 0;
    virtual void ReleaseBuffer(std::shared_ptr<OckHmmHMOBuffer> buffer) = 0;
    static std::shared_ptr<OckHmmSubHMObject> CreateSubHmo(std::shared_ptr<OckHmmSubHMObject> subHmoObject,
        uint64_t offset, uint64_t length);
};

class OckHmmHMObject : public OckHmmSubHMObject
{

public:
    virtual ~OckHmmHMObject() noexcept = default;
    virtual OckHmmHMOObjectID GetId(void) const = 0;
    virtual OckHmmDeviceID IntimateDeviceID(void) const = 0;
    static std::shared_ptr<std::vector<std::shared_ptr<OckHmmSubHMObject>>> CreateSubHmoList(
        std::shared_ptr<OckHmmHMObject> hmo, uint64_t subHmoBytes);
    static std::shared_ptr<OckHmmSubHMObject> CreateSubHmo(std::shared_ptr<OckHmmSubHMObject> subHmoObject,
        uint64_t offset, uint64_t length);        
};

std::ostream &operator<<(std::ostream &os, OckHmmSubHMObject &hmo);
std::ostream &operator<<(std::ostream &os, OckHmmHMObject &hmo);
std::ostream &operator<<(std::ostream &os, OckHmmHMOBuffer &buffer);
std::ostream &operator<<(std::ostream &os, std::shared_ptr<OckHmmSubHMObject> &hmo);
std::ostream &operator<<(std::ostream &os, std::shared_ptr<OckHmmHMObject> &hmo);
std::ostream &operator<<(std::ostream &os, std::shared_ptr<OckHmmHMOBuffer> &buffer);

}
}
#endif